package weaver.splittable;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import weaver.splittable.biz.STBizInterceptor;
import weaver.splittable.filter.STFilter;
import weaver.splittable.modal.STInterceptResult;

import java.util.Collection;
import java.util.Map;

/**
 * 分表组件拦截SQL的入口
 * author: YUEYANG 2023-01-12
 */
public class STInterceptor {

    private static final Logger LOGGER = Logger.getLogger(STConfig.LOGGER_NAME);

    public static STInterceptResult intercept(String sql) {

        Long startTime = System.currentTimeMillis();

        boolean isReplaced = false;

        // 基础拦截判断
        if (!needIntercept(sql)){
            return new STInterceptResult(false, sql);
        }

        // 判断SQL中是否有快表标识
        if (sql.contains(STConfig.FAST_DATA_SIGN)) {
            return new STInterceptResult(false, sql);
        }

        // 判断SQL中是否有全量表标识
        if (sql.contains(STConfig.FULL_DATA_SIGN)) {
            sql = replaceSQL(sql);
            return new STInterceptResult(true, sql);
        }

        // 判断是否为默认全量地址或默认快速地址，如果是直接替换返回
        String requestURL = STFilter.REQUEST_URL.get();
        if (StringUtils.isNotBlank(requestURL)) {
            if (STConfig.FAST_DATA_API_SET.contains(requestURL.toLowerCase())) {
                return new STInterceptResult(false, sql);
            }
            if (STConfig.FULL_DATA_API_SET.contains(requestURL.toLowerCase())) {
                sql = replaceSQL(sql);
                return new STInterceptResult(true, sql);
            }
        }

        // 过所有业务拦截器
        for (STBizInterceptor interceptor: STContext.BIZ_INTERCEPTORS()) {
            if (interceptor.needIntercept(sql)) {
                STInterceptResult interceptResult = interceptor.intercept(sql);
                sql = interceptResult.getSql();
                isReplaced = interceptResult.isReplace();
            }
        }

        Long endTime = System.currentTimeMillis();

        if (STConfig.IS_LOG && isReplaced) {
            Long costTime = endTime - startTime;
            LOGGER.info("STInterceptor replaced cost:"+ costTime +"ms, sql:" + sql);
        }

        return new STInterceptResult(isReplaced, sql);
    }

    public static STInterceptResult intercept(String sql, Map<Integer, Object> params) {
        // 基础拦截判断
        if (!needIntercept(sql)){
            return new STInterceptResult(false, sql);
        }
        if (params.size() < 1) {
            return intercept(sql);
        }
        String originSQL = sql;
        sql = getSqlWithParams(sql, params);
        STInterceptResult result = intercept(sql);
        if (result.isReplace()) {
            originSQL = replaceSQL(originSQL);
        }
        return new STInterceptResult(result.isReplace(), originSQL);
    }

    public static STInterceptResult procIntercept(String sql) {

        LOGGER.info("STInterceptor Proc Intercept:" + sql);

        // 基础判断 未安装直接返回 SQL为空直接返回
        if (!STInstaller.isInstalled() || StringUtils.isBlank(sql)) {
            return new STInterceptResult(false, sql);
        }

        // 如果配置中有要执行的Proc直接替换返回
        for (Map.Entry<String, String> procReplace: STConfig.PROC_REPLACE_MAP.entrySet()) {
            String oldProc = procReplace.getKey();
            String newProc = procReplace.getValue();

            if (sql.contains(oldProc)) {
                sql = sql.replace(oldProc, newProc);
                return new STInterceptResult(true, sql);
            }
        }

        return new STInterceptResult(false, sql);
    }

    private static String replaceSQL(String sql) {
        for (String tableName: STContext.SPLIT_TABLES().keySet()) {
            String tableNameRegex = "(?i)" + tableName;
            sql = sql.replaceAll(" " + tableNameRegex + " "," " + tableName + "_all ");
            sql = sql.replaceAll(" " + tableNameRegex + ","," " + tableName + "_all,");
            sql = sql.replaceAll("," + tableNameRegex + " ","," + tableName + "_all ");
            sql = sql.replaceAll("," + tableNameRegex + ",","," + tableName + "_all,");
            sql = sql.replaceAll(" " + tableNameRegex + "\\."," " + tableName + "_all.");
        }
        return sql;
    }

    public static boolean needIntercept(String sql) {
        // 基础判断 未安装直接返回 SQL为空直接返回
        if (!STInstaller.isInstalled() || StringUtils.isBlank(sql)) {
            return false;
        }

        // 业务拦截器判断
        for (STBizInterceptor bizInterceptor: STContext.BIZ_INTERCEPTORS()) {
            if (bizInterceptor.needIntercept(sql)){
                return true;
            }
        }

        return false;
    }

    public static String getSqlWithParams(String sql, Map<Integer, Object> params) {
        sql = sql.replace("?", "'%s'");
        Collection<Object> values = params.values();
        sql = String.format(sql, values.toArray());
        return sql;
    }



}
